A Brief Introduction to Git Commit Conventions
Most Git commit conventions on the internet today originate from the Angular team's format, which has evolved into many versions over time. Although this information is widely available online, I decided to write an article to document it to prevent it from being lost—after all, the articles I read five years ago are nowhere to be found now. The current "[Angular Commit Format]" is as follows: (https://github.com/angular/angular/blob/main/CONTRIBUTING.md).
Commit Format
The Angular Commit Format is divided into three parts: header, body, and footer, separated by blank lines. The header is mandatory, the body depends on the header's type (mandatory if the type is docs), and the footer is optional.
<header>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>Header
The header format is as follows (excerpted from the Angular Commit Format content):
<type>(<scope>): <short summary>
│ │ │
│ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
│ │
│ └─⫸ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|
│ elements|forms|http|language-service|localize|platform-browser|
│ platform-browser-dynamic|platform-server|router|service-worker|
│ upgrade|zone.js|packaging|changelog|docs-infra|migrations|
│ devtools
│
└─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|testType
The type is used to categorize commits. Categories have varied over time; the current table is summarized below. The main differences are that style and chore have been removed, and CI/CD has been separated from build:
| Type | Description | New Description |
|---|---|---|
| feat | New feature | New feature |
| fix | Bug fix | Bug fix |
| docs | Documentation only changes | Documentation only changes |
| style | Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.) | |
| refactor | A code change that neither fixes a bug nor adds a feature | A code change that neither fixes a bug nor adds a feature |
| test | Adding missing tests or correcting existing tests | Adding missing tests or correcting existing tests |
| perf | A code change that improves performance | A code change that improves performance |
| build | Changes that affect the build system, CI configuration, or external dependencies (example scopes: gulp, broccoli, npm) | Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) |
| chore | Other changes that don't modify src or test files | |
| ci | Changes to CI configuration files and scripts (example: CircleCI, SauceLabs) |
Scope
The scope indicates the name of the affected npm package. This is defined specifically for Angular and may not apply to other programming languages. For me, in most cases, I choose to omit it or label it with the name of the project being changed.
Short Summary (Subject)
The Short Summary is a concise description of the change. The Angular specification is as follows:
- use the imperative, present tense: "change" not "changed" nor "changes"
- don't capitalize the first letter
- no dot (.) at the end
However, since I write in Traditional Chinese, I simply omit the period at the end of the sentence.
Body
The original text from the Angular team is as follows:
Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes".
Explain the motivation for the change in the commit message body. This commit message should explain why you are making the change. You can include a comparison of the previous behavior with the new behavior in order to illustrate the impact of the change.
Since I write in Chinese, there is no tense issue. In practice, unless the content is complex or requires a specific explanation of the reason for the change, I omit the Body. Recently, a friend mentioned using Visual Studio's Copilot to help generate commit messages (if you have a Copilot subscription), so I might start using the generated message as a base for the Body.
Footer
The footer can contain information about breaking changes and deprecations, and can also be used to reference GitHub issues, Jira tickets, and other PRs. For example:
BREAKING CHANGE: <breaking change summary>
<BLANK LINE>
<breaking change description + migration instructions>
<BLANK LINE>
<BLANK LINE>
Fixes #<issue number>Or:
DEPRECATED: <what is deprecated>
<BLANK LINE>
<deprecation description + recommended update path>
<BLANK LINE>
<BLANK LINE>
Closes #<pr number>BREAKING CHANGE is used for major incompatible changes, and DEPRECATED is used to describe deprecated content.
In most cases, the Footer is only used to link to a requirement ticket number; the specific linking method depends on the Issue Tracker being used.
For example, in GitHub, you can use the following keywords to link and close an issue. See the GitHub documentation "Linking a pull request to an issue".
- close
- closes
- closed
- fix
- fixes
- fixed
- resolve
- resolves
- resolved
In GitLab, you can link in the following ways, replacing 123 with the corresponding ID:
- Link Issue: #123
- Link MR: !123
- Link Snippet: $123
GitLab also supports Closes #123 or Fixes #123 to close the corresponding issue when merging the branch. See the GitLab documentation "Tutorial: It's all connected in GitLab".
Personally, since PRs or MRs might not be linked to an Issue Tracker, or I might want to control the association manually, I use the prefix issue so that it is semantically clear that #123 is associated with an issue.
TIP
Keywords like close are case-insensitive. The examples in the documentation use uppercase at the start of the sentence; if you look closely, they are lowercase when appearing in the middle of a sentence.
Commit Template
The above is a brief introduction to the current mainstream commit conventions. However, in actual operation, you might forget some less frequently used content, such as the types I often forget. Git supports a default Commit Template, which can help us standardize the commit message format.
Configuration Method
First, create a file named .gitmessage.txt. The filename cannot be changed. The content is as follows and can be adjusted according to your needs:
<type>(<scope>): <subject>
# -- Type --
# Must be one of the following:
#
# feat: New feature
# fix: Bug fix
# docs: Documentation only changes
# style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.)
# refactor: A code change that neither fixes a bug nor adds a feature
# perf: A code change that improves performance
# test: Adding missing tests or correcting existing tests
# build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
# chore: Other changes that don't modify src or test files
# ci: Changes to CI configuration files and scripts (example: CircleCI, SauceLabs)
#
# -- Scope --
# The scope can be anything that specifies the location of the commit changes, e.g., init, runner, watcher, config, web-server, proxy, etc.
#
# -- Subject --
# The subject contains a concise description of the change:
# Use the imperative, present tense: "change" not "changed" nor "changes"
# Do not capitalize the first letter
# Do not use a period at the end
#
# -- Body --
# Just as in the subject, use the imperative, present tense: "change" not "changed" nor "changes".
# The body should contain the motivation for the change and contrast it with the previous behavior.
#
# -- Footer --
# The footer should contain information about Breaking Changes and is also a reference for closing GitHub issues.
# Breaking Changes should start with the word "BREAKING CHANGE": followed by a space or two newlines. Then use the rest of the commit message.
# Deprecated should start with the word "DEPRECATED": followed by a space or two newlines. Then use the rest of the commit message.Next, open Git Bash and enter the following commands (where ~/ defaults to C:\Users\{Windows Username}, or replace ~/ with the full path where you want to place the file):
git config --global commit.template ~/.gitmessage.txt
git config --global commit.cleanup stripExplanation:
git config: This is the Git configuration command used to view and set Git configuration options.--global: This flag indicates that the setting will be applied globally, i.e., to all Git repositories. If this flag is not used, the setting will only take effect in the current Git repository.commit.template: Used to specify the location of the template file for commit messages.commit.cleanup: Used to specify how to handle commit messages during a commit. The default iswhitespace, which does not ignore comment lines.strip: This is the value for thecommit.cleanupoption, which means that comment lines and extra blank lines in the commit message are removed during the commit.
After execution, the following content will be added to the global .gitconfig. The global .gitconfig is stored by default in the user's account directory on Windows, for example: C:\Users\{Windows Username}.
[commit]
cleanup = strip
template = {Specified Path}/.gitmessage.txtIf the command is entered without --global, this content will be generated in the ./.git/config file of that repository.
TIP
If template is set to ./.gitmessage.txt, Git will use the .gitmessage.txt file in the root directory of the repository as the Commit Template.
Git has three levels of configuration:
- System configuration:
- Location:
C:\Program Files\Git\etc\gitconfig. - Lowest priority. This setting affects all users and projects on the entire system. It is usually a global setting configured by the system administrator and is suitable for system-wide Git behavior conventions.
- Location:
- Global configuration:
C:\Users\{Windows Username}\.gitconfig:- Second highest priority. This setting applies to a single user but is overridden by Local settings. It is commonly used to set personal Git options and affects all repositories unless overridden by Local settings.
- Local configuration:
.git\config- Highest priority. This setting is only valid for the current project and overrides Global and System settings. Since its scope is limited to a specific repository, it is particularly useful for cases where special settings are needed for a project.
TIP
The three filenames are all different XD
Practical Usage
When you enter git commit in Git Bash, the message hint: Waiting for your editor to close the file... will appear, and a text editor will open containing the content of .gitmessage.txt along with the following information:
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch main
# Your branch is up to date with 'origin/main'.
#
# Changes to be committed:
# modified: "{Modified Filename}"The blank line added at the end of .gitmessage.txt is to separate it from this section of information. This section mainly explains that you should enter a commit message, that lines starting with # will be ignored, and provides a list of modified files.
Once you have modified the file and saved it, the content of the file will be used as the commit message.
If you use other Git version control software, it may not necessarily ignore lines starting with #, so you need to set commit.cleanup strip.
Currently, the version control software I know that supports Commit Templates is as follows:
GitKraken: In the repository tab, click File => Preferences... => Commit. The Commit Template setting will be displayed. If
commit.cleanup stripis not set, remember to check "Removes comments from commit messages" to ignore lines starting with#.Tortoisegit: When
commit.cleanupiswhitespace, commits do not ignore lines starting with#.Git Extensions: When
commit.cleanupiswhitespace, commits still ignore lines starting with#(thanks to a colleague for testing).Sourcetree:
- Supported in Mac version 4.2.8 (thanks to a colleague for testing); supported in Windows version 3.4.20 and later.
- When
commit.cleanupiswhitespace, commits still ignore lines starting with#.
TIP
Sourcetree version 3.4.18 did not yet support Git Template. However, I saw on 2024/6/27 that the official team closed many Jira tickets that people had been asking for for years, stating that Commit template message has been resolved, so it might be supported in a future version.
Sourcetree 3.4.20 has added support. See Sourcetree release notes.
SourceTree 3.4.20 [17 September 2024]
- Changes: Supporting git commit template feature
- Changes: Upgrade to Git 2.46.0 and Git LFS to 3.5.1
- Fixed: 'Push changes immediately' checkbox is disabled in No Staging View
- Fixed: Arbitrary code execution vulnerability
- Fixed: Interactive rebase always aborting when a merge is necessary
- Fixed: Silent crash when creating a hotfix
- Fixed: Sourcetree diff treats large .sql files as binary
- Fixed: Windows Line breaks are replaced with Unix breaks on "Discard Hunk" click
Reverting Settings
You can use the following command to remove the Git Template setting:
git config --unset --global commit.templateUse the following command to restore the setting to ignore comment lines:
git config --global commit.cleanup whitespaceChange Log
- 2024-07-23 Initial document creation.
- 2024-09-20
- Updated to note that Windows Sourcetree 3.4.20 supports the Git Commit Template feature.
- Corrected the explanation of the configuration file location.
